home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
DJGPP
/
DJ111M2.ZIP
/
go32
/
ed
/
syms.c
Wrap
C/C++ Source or Header
|
1994-01-09
|
17KB
|
758 lines
/* This is file SYMS.C */
/*
** Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
**
** This file is distributed under the terms listed in the document
** "copying.dj", available from DJ Delorie at the address above.
** A copy of "copying.dj" should accompany this file; if not, a copy
** should be available from where this file was obtained. This file
** may not be distributed without a verbatim copy of "copying.dj".
**
** This file is distributed WITHOUT ANY WARRANTY; without even the implied
** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <dos.h>
#include <io.h>
#include "ed.h"
#include "coff.h"
#include "syms.h"
#include "stab.h"
#define DO_SYMS 1
int undefined_symbol=0;
#define Ofs(n) ((int)&(((TSS *)0)->n))
struct {
char *name;
int size;
int ofs;
} regs[] = {
"%eip", 4, Ofs(tss_eip),
"%eflags", 4, Ofs(tss_eflags),
"%eax", 4, Ofs(tss_eax),
"%ebx", 4, Ofs(tss_ebx),
"%ecx", 4, Ofs(tss_ecx),
"%edx", 4, Ofs(tss_edx),
"%esp", 4, Ofs(tss_esp),
"%ebp", 4, Ofs(tss_ebp),
"%esi", 4, Ofs(tss_esi),
"%edi", 4, Ofs(tss_edi),
"%ax", 2, Ofs(tss_eax),
"%bx", 2, Ofs(tss_ebx),
"%cx", 2, Ofs(tss_ecx),
"%dx", 2, Ofs(tss_edx),
"%ah", 1, Ofs(tss_eax)+1,
"%bh", 1, Ofs(tss_ebx)+1,
"%ch", 1, Ofs(tss_ecx)+1,
"%dh", 1, Ofs(tss_edx)+1,
"%al", 1, Ofs(tss_eax),
"%bl", 1, Ofs(tss_ebx),
"%cl", 1, Ofs(tss_ecx),
"%dl", 1, Ofs(tss_edx),
0, 0, 0
};
#if !DO_SYMS
void syms_init(char *fname) {}
void syms_list(int byval) {}
void syms_listwild(char *pattern) {}
word32 syms_name2val(char *name)
{
if (isdigit(name[0]))
{
int v;
if (strncmp(name, "0x", 2) == 0)
sscanf(name+2, "%x", &v);
else
sscanf(name, "%d", &v);
undefined_symbol = 0;
return v;
}
else
{
undefined_symbol = 1;
return 0;
}
}
char *syms_val2name(word32 val, word32 *delta)
{
static char noname_buf[20];
sprintf(noname_buf, "%#lx", val);
*delta = 0;
return noname_buf;
}
char *syms_val2line(word32 val, int *lineret, int exact)
{
return 0;
}
#else
/* From the file */
typedef struct SYM_ENTRY {
word32 string_off;
word8 type;
word8 other;
word16 desc;
word32 val;
} SYM_ENTRY;
static FILHDR f_fh;
static AOUTHDR f_ah;
static SCNHDR *f_sh;
static SYMENT *f_symtab;
static SYM_ENTRY *f_aoutsyms;
static AUXENT *f_aux;
static LINENO **f_lnno;
static char *f_string_table;
static char *f_types;
/* built internally */
typedef struct {
char *filename;
word32 first_address;
word32 last_address;
LINENO *lines;
int num_lines;
} FileNode;
static FileNode *files;
static int num_files;
typedef struct SymNode {
char *name;
word32 address;
char type_c;
} SymNode;
static SymNode *syms;
static SymNode *syms_byname;
static int num_syms;
static int syms_sort_bn(const void *a, const void *b)
{
SymNode *sa = (SymNode *)a;
SymNode *sb = (SymNode *)b;
return strcmp(sa->name, sb->name);
}
static int syms_sort_bv(const void *a, const void *b)
{
SymNode *sa = (SymNode *)a;
SymNode *sb = (SymNode *)b;
return sa->address - sb->address;
}
static char *symndup(char *s, int len)
{
char c = s[len], *rv;
s[len] = 0;
rv = strdup(s);
s[len] = c;
return rv;
}
static int valid_symbol(int i)
{
char *sn;
if (f_symtab[i].e.e.e_zeroes)
sn = f_symtab[i].e.e_name;
else
sn = f_string_table + f_symtab[i].e.e.e_offset;
if (sn[0] != '_')
return 0;
if (strncmp(sn, "___gnu_compiled", 15) == 0)
return 0;
if (strcmp(sn, "__DYNAMIC") == 0)
return 0;
return 1;
}
static void process_coff(FILE *fd, long ofs)
{
int i, f, s, f_pending;
LINENO *l;
int l_pending;
word32 strsize;
char *name;
fseek(fd, ofs, 0);
fread(&f_fh, 1, FILHSZ, fd);
fread(&f_ah, 1, AOUTSZ, fd);
f_sh = (SCNHDR *)malloc(f_fh.f_nscns * SCNHSZ);
f_types = (char *)malloc(f_fh.f_nscns);
f_lnno = (LINENO **)malloc(f_fh.f_nscns * sizeof(LINENO *));
fread(f_sh, f_fh.f_nscns, SCNHSZ, fd);
for (i=0; i<f_fh.f_nscns; i++)
{
if (f_sh[i].s_flags & STYP_TEXT)
f_types[i] = 'T';
if (f_sh[i].s_flags & STYP_DATA)
f_types[i] = 'D';
if (f_sh[i].s_flags & STYP_BSS)
f_types[i] = 'B';
if (f_sh[i].s_nlnno)
{
fseek(fd, ofs + f_sh[i].s_lnnoptr, 0L);
f_lnno[i] = (LINENO *)malloc(f_sh[i].s_nlnno * LINESZ);
fread(f_lnno[i], LINESZ, f_sh[i].s_nlnno, fd);
}
else
f_lnno[i] = 0;
}
fseek(fd, ofs + f_fh.f_symptr + f_fh.f_nsyms * SYMESZ, 0);
fread(&strsize, 1, 4, fd);
f_string_table = (char *)malloc(strsize);
fread(f_string_table+4, 1, strsize-4, fd);
f_string_table[0] = 0;
fseek(fd, ofs+f_fh.f_symptr, 0);
f_symtab = (SYMENT *)malloc(f_fh.f_nsyms * SYMESZ);
fread(f_symtab, SYMESZ, f_fh.f_nsyms, fd);
f_aux = (AUXENT *)f_symtab;
num_syms = num_files = 0;
for (i=0; i<f_fh.f_nsyms; i++)
{
switch (f_symtab[i].e_sclass)
{
case C_FILE:
num_files++;
break;
case C_EXT:
case C_STAT:
if (!valid_symbol(i))
break;
num_syms++;
break;
}
i += f_symtab[i].e_numaux;
}
files = (FileNode *)malloc(num_files * sizeof(FileNode));
syms = (SymNode *)malloc(num_syms * sizeof(SymNode));
f = s = f_pending = l_pending = 0;
for (i=0; i<f_fh.f_nsyms; i++)
{
switch (f_symtab[i].e_sclass)
{
case C_FILE:
if (f_aux[i+1].x_file.x_n.x_zeroes)
files[f].filename = symndup(f_aux[i+1].x_file.x_fname, 16);
else
files[f].filename = f_string_table + f_aux[i+1].x_file.x_n.x_offset;
files[f].lines = 0;
f_pending = 1;
f++;
break;
case C_EXT:
case C_STAT:
if (f_symtab[i].e.e.e_zeroes)
name = f_symtab[i].e.e_name;
else
name = f_string_table + f_symtab[i].e.e.e_offset;
if (f_pending && strcmp(name, ".text") == 0)
{
files[f-1].first_address = f_symtab[i].e_value;
files[f-1].last_address = f_symtab[i].e_value + f_aux[i+1].x_scn.x_scnlen - 1;
files[f-1].num_lines = f_aux[i+1].x_scn.x_nlinno;
f_pending = 0;
}
if (ISFCN(f_symtab[i].e_type))
{
int scn = f_symtab[i].e_scnum - 1;
l = f_lnno[scn] + ((f_aux[i+1].x_sym.x_fcnary.x_fcn.x_lnnoptr - f_sh[scn].s_lnnoptr)/LINESZ);
l_pending = 1;
l->l_addr.l_paddr = f_symtab[i].e_value;
}
if (!valid_symbol(i))
break;
syms[s].address = f_symtab[i].e_value;
if (f_symtab[i].e.e.e_zeroes)
syms[s].name = symndup(f_symtab[i].e.e_name, 8);
else
syms[s].name = f_string_table + f_symtab[i].e.e.e_offset;
switch (f_symtab[i].e_scnum)
{
case 1 ... 10:
syms[s].type_c = f_types[f_symtab[i].e_scnum-1];
break;
case N_UNDEF:
syms[s].type_c = 'U';
break;
case N_ABS:
syms[s].type_c = 'A';
break;
case N_DEBUG:
syms[s].type_c = 'D';
break;
}
if (f_symtab[i].e_sclass == C_STAT)
syms[s].type_c += 'a' - 'A';
s++;
break;
case C_FCN:
if (f_pending && files[f-1].lines == 0)
{
files[f-1].lines = l;
}
if (l_pending)
{
int lbase = f_aux[i+1].x_sym.x_misc.x_lnsz.x_lnno - 1;
int i2;
l->l_lnno = lbase;
l++;
for (i2=0; l[i2].l_lnno; i2++)
l[i2].l_lnno += lbase;
l_pending = 0;
}
break;
}
i += f_symtab[i].e_numaux;
}
}
static void process_aout(FILE *fd, long ofs)
{
GNU_AOUT header;
word32 string_table_length;
int nsyms, i, f, s, l;
fseek(fd, ofs, 0);
fread(&header, 1, sizeof(header), fd);
fseek(fd, ofs + sizeof(header) + header.tsize + header.dsize + header.txrel + header.dtrel, 0);
nsyms = header.symsize / sizeof(SYM_ENTRY);
f_aoutsyms = (SYM_ENTRY *)malloc(header.symsize);
fread(f_aoutsyms, 1, header.symsize, fd);
fread(&string_table_length, 1, 4, fd);
f_string_table = (char *)malloc(string_table_length);
fread(f_string_table+4, 1, string_table_length-4, fd);
f_string_table[0] = 0;
num_files = num_syms = 0;
for (i=0; i<nsyms; i++)
{
char *symn = f_string_table + f_aoutsyms[i].string_off;
char *cp;
switch (f_aoutsyms[i].type & ~N_EXT)
{
case N_SO:
if (symn[strlen(symn)-1] == '/')
break;
num_files++;
break;
case N_TEXT:
cp = symn + strlen(symn) - 2;
if (strncmp(symn, "___gnu", 6) == 0 ||
strcmp(cp, "d.") == 0 /* as in gcc_compiled. */ ||
strcmp(cp, ".o") == 0)
break;
case N_DATA:
case N_ABS:
case N_BSS:
case N_FN:
case N_SETV:
case N_SETA:
case N_SETT:
case N_SETD:
case N_SETB:
case N_INDR:
num_syms ++;
break;
}
}
syms = (SymNode *)malloc(num_syms * sizeof(SymNode));
memset(syms, num_syms * sizeof(SymNode), 0);
files = (FileNode *)malloc(num_files * sizeof(FileNode));
memset(files, num_files * sizeof(FileNode), 0);
f = s = 0;
for (i=0; i<nsyms; i++)
{
char c, *cp;
char *symn = f_string_table + f_aoutsyms[i].string_off;
switch (f_aoutsyms[i].type & ~N_EXT)
{
case N_SO:
if (symn[strlen(symn)-1] == '/')
break;
if (f && files[f-1].last_address == 0)
files[f-1].last_address = f_aoutsyms[i].val - 1;
files[f].filename = symn;
files[f].first_address = f_aoutsyms[i].val;
f ++;
break;
case N_SLINE:
files[f-1].num_lines++;
break;
case N_TEXT:
cp = symn + strlen(symn) - 2;
if (strncmp(symn, "___gnu", 6) == 0 ||
strcmp(cp, "d.") == 0 /* as in gcc_compiled. */ ||
strcmp(cp, ".o") == 0)
{
if (f && files[f-1].last_address == 0)
files[f-1].last_address = f_aoutsyms[i].val - 1;
break;
}
c = 't';
goto sym_c;
case N_DATA:
c = 'd';
goto sym_c;
case N_ABS:
c = 'a';
goto sym_c;
case N_BSS:
c = 'b';
goto sym_c;
case N_FN:
c = 'f';
goto sym_c;
case N_SETV:
c = 'v';
goto sym_c;
case N_SETA:
c = 'v';
goto sym_c;
case N_SETT:
c = 'v';
goto sym_c;
case N_SETD:
c = 'v';
goto sym_c;
case N_SETB:
c = 'v';
goto sym_c;
case N_INDR:
c = 'i';
sym_c:
syms[s].name = symn;
syms[s].address = f_aoutsyms[i].val;
syms[s].type_c = (f_aoutsyms[i].type & N_EXT) ? (c+'A'-'a') : c;
s ++;
break;
}
}
l = f = 0;
for (i=0; i<nsyms; i++)
{
char c, *cp;
char *symn = f_string_table + f_aoutsyms[i].string_off;
switch (f_aoutsyms[i].type & ~N_EXT)
{
case N_SO:
if (symn[strlen(symn)-1] == '/')
break;
files[f].lines = (LINENO *)malloc(files[f].num_lines * sizeof(LINENO));
f++;
l = 0;
break;
case N_SLINE:
files[f-1].lines[l].l_addr.l_paddr = f_aoutsyms[i].val;
files[f-1].lines[l].l_lnno = f_aoutsyms[i].desc;
l ++;
break;
}
}
}
static void process_file(FILE *fd, long ofs)
{
short s, exe[2];
fseek(fd, ofs, 0);
fread(&s, 1, 2, fd);
switch (s)
{
case 0x5a4d: /* .exe */
fread(exe, 2, 2, fd);
ofs += (long)exe[1] * 512L;
if (exe[0])
ofs += (long)exe[0] - 512L;
process_file(fd, ofs);
break;
case 0x014c: /* .coff */
process_coff(fd, ofs);
break;
case 0x010b: /* a.out ZMAGIC */
case 0x0107: /* a.out object */
process_aout(fd, ofs);
break;
}
}
void syms_init(char *fname)
{
FILE *fd = fopen(fname, "rb");
if (fd == 0)
{
perror(fname);
}
else
{
process_file(fd, 0);
syms_byname = (SymNode *)malloc(num_syms * sizeof(SymNode));
memcpy(syms_byname, syms, num_syms * sizeof(SymNode));
qsort(syms_byname, num_syms, sizeof(SymNode), syms_sort_bn);
qsort(syms, num_syms, sizeof(SymNode), syms_sort_bv);
fclose(fd);
}
}
int lookup_sym_byname(char *name, int idx, int ofs)
{
int below, above;
char ch = name[idx];
name[idx] = 0;
below = -1;
above = num_syms;
while (above - below > 1)
{
int mid = (above + below) / 2;
int c = 0;
if (ofs)
c = '_' - syms_byname[mid].name[0];
if (c == 0)
c = strcmp(name, syms_byname[mid].name+ofs);
if (c == 0)
{
name[idx] = ch;
return mid;
}
if (c < 0)
above = mid;
else
below = mid;
}
name[idx] = ch;
return -1;
}
word32 syms_name2val(char *name)
{
int cval, idx, sign=1, i;
word32 v;
char *cp;
undefined_symbol = 0;
idx = 0;
sscanf(name, "%s", name);
if (name[0] == 0)
return 0;
if (name[0] == '-')
{
sign = -1;
name++;
}
else if (name[0] == '+')
{
name++;
}
if (isdigit(name[0]))
{
if (sign == -1)
return -strtol(name, 0, 0);
return strtol(name, 0, 0);
}
cp = strpbrk(name, "+-");
if (cp)
idx = cp-name;
else
idx = strlen(name);
if (name[0] == '%') /* register */
{
for (i=0; regs[i].name; i++)
if (strncmp(name, regs[i].name, idx) == 0)
{
switch (regs[i].size)
{
case 1:
v = *(word8 *)((word8 *)(&a_tss) + regs[i].ofs);
break;
case 2:
v = *(word16 *)((word8 *)(&a_tss) + regs[i].ofs);
break;
case 4:
v = *(word32 *)((word8 *)(&a_tss) + regs[i].ofs);
break;
}
return v + syms_name2val(name+idx);
}
}
for (i=0; i<idx; i++)
if (name[i] == '#')
{
int f;
int lnum, l;
sscanf(name+i+1, "%d", &lnum);
for (f=0; f<num_files; f++)
{
if ((strncmp(name, files[f].filename, i) == 0) && (files[f].filename[i] == 0))
{
for (l=0; l<files[f].num_lines; l++)
{
if (files[f].lines[l].l_lnno == lnum)
return files[f].lines[l].l_addr.l_paddr + syms_name2val(name+idx);
}
printf("undefined line number %.*s\n", idx, name);
undefined_symbol = 1;
return 0;
}
}
printf("Undefined file name %.*s\n", i, name);
undefined_symbol = 1;
return 0;
}
i = lookup_sym_byname(name, idx, 0);
if (i == -1)
i = lookup_sym_byname(name, idx, 1);
if (i != -1)
return syms_byname[i].address * sign + syms_name2val(name+idx);
printf("Undefined symbol %.*s\n", idx, name);
undefined_symbol = 1;
return 0;
}
static char noname_buf[11];
char *syms_val2name(word32 val, word32 *delta)
{
static char buf[1000];
int above, below, mid;
if (delta)
*delta = 0;
if (num_syms <= 0)
goto noname;
above = num_syms;
below = -1;
while (above-below > 1)
{
mid = (above+below)/2;
if (syms[mid].address == val)
break;
if (syms[mid].address > val)
above = mid;
else
below = mid;
}
if (syms[mid].address > val)
{
if (mid == 0)
goto noname;
mid--; /* the last below was it */
}
if (mid < 0)
goto noname;
if (strcmp(syms[mid].name, "_end") == 0)
goto noname;
if (strcmp(syms[mid].name, "__end") == 0)
goto noname;
if (strcmp(syms[mid].name, "_etext") == 0)
goto noname;
if (delta)
*delta = val - syms[mid].address;
return syms[mid].name;
noname:
sprintf(noname_buf, "%#lx", val);
return noname_buf;
}
char *syms_val2line(word32 val, int *lineret, int exact)
{
int f, l;
for (f=0; f<num_files; f++)
{
if (val >= files[f].first_address && val <= files[f].last_address && files[f].lines)
{
for (l=files[f].num_lines-1; l >= 0 && files[f].lines[l].l_addr.l_paddr > val; l--);
if ((files[f].lines[l].l_addr.l_paddr != val) && exact)
return 0;
*lineret = files[f].lines[l].l_lnno;
return files[f].filename;
}
}
return 0;
}
void syms_listwild(char *pattern)
{
int linecnt = 0;
int lnum;
char *name;
int i, key;
for (i=0; i<num_syms; i++)
if (wild(pattern, syms_byname[i]))
{
if (++linecnt > 20)
{
printf("--- More ---");
fflush(stdout);
key = getkey();
printf("\r \r");
switch (key)
{
case ' ':
linecnt = 0;
break;
case 13:
linecnt--;
break;
case 'q':
case 27:
return;
}
}
printf("0x%08lx %c %s", syms_byname[i].address, syms_byname[i].type_c, syms_byname[i].name);
name = syms_val2line(syms_byname[i].address, &lnum, 0);
if (name)
printf(", line %d of %s", lnum, name);
putchar('\n');
}
}
#endif